home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #1 / Ham Radio 2000.iso / ham2000 / tcp_ip / ka9q / expiry / expire.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-05-15  |  6.4 KB  |  254 lines

  1. /* Expire old news articles */
  2.  
  3. /* Written by Bernie Roehl, May 1990 */
  4.  
  5. /* Works with the NNTPCLI by Anders Klemets and Bernie Roehl */
  6.  
  7. /* Two possible uses:
  8.  
  9.              EXPIRE filename [n,m,o]
  10.  
  11.    will expire only the give file.  If n,m,o are given, they specify the
  12.    number of kilobytes, articles, and days; those which are zero are taken
  13.    as unrestricted.
  14.  
  15.              EXPIRE directory [n,m,o [controlfile]]
  16.  
  17.    will expire all the .txt files under the given directory and all its
  18.    subdirectories, recursively.  The n,m,o parameter is the default set
  19.    of values as described above; these may be overridden by entries in
  20.    the controlfile, which are of the form
  21.  
  22.              filename n,m,o
  23.  
  24.    where 'filename' is the name of the .txt file containing the articles
  25.    and n,m,o are the values to override the defaults (on this file only).
  26.  */
  27.  
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #include <dir.h>
  31. #include <dos.h>
  32. #include <fcntl.h>
  33. #include <sys/stat.h>
  34. #include <sys/timeb.h>
  35. #include <string.h>
  36. #include <ctype.h>
  37. #include <time.h>
  38.  
  39. char *progname = "EXPIRE";
  40.  
  41. /* Default expiry values: */
  42.  
  43. int def_kilos = 32;   /* 32 kilobytes/group */
  44. int def_arts = 500;   /* 500 articles/group */
  45. int def_days =   7;   /* 7 days from arrival date */
  46.  
  47. void main(argc, argv)
  48. int argc;
  49. char *argv[];
  50.     {
  51.     struct stat statbuf;
  52.     void expire(), walk_dirs();
  53.     if (argc < 2) {
  54.         printf("%s: Correct usage is 'expire path [n,m,o [controlfile]]'\n", progname);
  55.         exit(2);
  56.         }
  57.     if (stat(argv[1], &statbuf)) {
  58.         printf("%s: Couldn't stat '%s'\n", progname, argv[1]);
  59.         exit(3);
  60.         }
  61.     if (argc > 2)
  62.         if (sscanf(argv[2], "%d,%d,%d", &def_kilos, &def_arts, &def_days) != 3) {
  63.             printf("%s: Syntax error in second argument (\"%s\")\n", progname, argv[2]);
  64.             exit(4);
  65.             }
  66.     if (statbuf.st_mode & S_IFREG)
  67.         expire(argv[1], def_kilos, def_arts, def_days);
  68.     else if (argc > 3) {
  69.         FILE *ctl;
  70.         if ((ctl = fopen(argv[3], "r")) == NULL) {
  71.             printf("%s: Could not open control file '%s'\n", progname, argv[3]);
  72.             exit(5);
  73.             }
  74.         walk_dirs(argv[1], ctl);
  75.         fclose(ctl);
  76.         }
  77.     else
  78.         walk_dirs(argv[1], NULL);
  79.     }
  80.  
  81. void expire(char *filename, int kilos, int arts, int days)
  82.     {
  83.     char buff[80], dir[80], *p, *q, *d;
  84.     FILE *ng;
  85.     long lowater;
  86.     strcpy(dir, filename);
  87.     if ((p = strrchr(dir, '\\')) != NULL) {
  88.         *p++ = '\0';
  89.         d = dir;
  90.         }
  91.     else {
  92.         p = dir;
  93.         d = ".";
  94.         }
  95.     if ((q = strchr(p, '.')) != NULL)
  96.         *q = '\0';
  97.     if (mlock(d, p)) {
  98.         printf("%s: Couldn't get lock on '%s'\n", progname, filename);
  99.         return;
  100.         }
  101.     if ((ng = fopen(filename, "r")) == NULL) {
  102.         printf("%s: Couldn't open '%s'\n", progname, filename);
  103.         rmlock(d, p);
  104.         return;
  105.         }
  106.     lowater = 0L;
  107.     if (kilos) {
  108.         long pos;
  109.         fseek(ng, 0L, SEEK_END);
  110.         if (ftell(ng) > kilos * 1024L) {  /* File larger than limit? */
  111.             fseek(ng, -kilos * 1024L, SEEK_END);
  112.             for (pos = ftell(ng); fgets(buff, sizeof(buff), ng); pos = ftell(ng))
  113.                 if (!strnicmp(buff, "From ", 5))
  114.                     break;
  115.             if (pos > lowater)
  116.                 lowater = pos;
  117.             }
  118.         }
  119.     if (arts) {
  120.         long pos;
  121.         int nart = 0;
  122.         rewind(ng);
  123.         while (fgets(buff, sizeof(buff), ng))  /* count up the articles */
  124.             if (!strnicmp(buff, "From ", 5))
  125.                 ++nart;
  126.         if (nart > arts) {
  127.             nart -= arts;  /* nart is now the number of articles to delete */
  128.             rewind(ng);
  129.             for (pos = ftell(ng); fgets(buff, sizeof(buff), ng); pos = ftell(ng))
  130.                 if (!strnicmp(buff, "From ", 5))
  131.                     if (--nart < 0)
  132.                         break;
  133.             if (pos > lowater)
  134.                 lowater = pos;
  135.             }
  136.         }
  137.     if (days)  {
  138.         long pos;
  139.         rewind(ng);
  140.         for (pos = ftell(ng); fgets(buff, sizeof(buff), ng); pos = ftell(ng))
  141.             if (!strnicmp(buff, "From ", 5)) {
  142.                 char *p;
  143.                 struct timeb t;
  144.                 long now, then;
  145.                 if ((p = strrchr(buff, ' ')) == NULL)  /* weird format... no blanks! */
  146.                     continue;
  147.                 if (!isdigit(*++p))  /* missing or invalid timestamp */
  148.                     continue;
  149.                 then = atol(p);
  150.                 ftime(&t);
  151.                 now = t.time;
  152.                 if ((now - then) > (days * 24L * 60L * 60L)) {
  153.                     if (pos > lowater)
  154.                         lowater = pos;
  155.                     }
  156.                 }
  157.         }
  158.     if (lowater > 0L) {
  159.         FILE *tmpf;
  160.         char tfile[80];
  161.         sprintf(tfile, "%s/%s.tmp", d, p);
  162.         unlink(tfile);
  163.         if ((tmpf = fopen(tfile, "w")) == NULL) {
  164.             printf("%s: Could not create '%s'\n", progname, tfile);
  165.             fclose(ng);
  166.             rmlock(d, p);
  167.             return;
  168.             }
  169.         fseek(ng, lowater, SEEK_SET);
  170.         while (fgets(buff, sizeof(buff), ng))
  171.             fputs(buff, tmpf);
  172.         fclose(tmpf);
  173.         fclose(ng);
  174.         sprintf(buff, "%s/%s.txt", d, p);
  175.         unlink(buff);
  176.         rename(tfile, buff);
  177.         }
  178.     else
  179.         fclose(ng);
  180.     rmlock(d, p);
  181.     }
  182.  
  183. void walk_dirs(char *dir, FILE *ctl)
  184.     {
  185.     char work[80];
  186.     struct ffblk ff;
  187.  
  188.     sprintf(work, "%s/*.txt", dir);
  189.     if (findfirst(work, &ff, 0) == 0)
  190.         do {
  191.             int kilos, arts, days;
  192.             char input_line[100];
  193.             kilos = def_kilos; arts = def_arts; days = def_days;
  194.             sprintf(work, "%s/%s", dir, ff.ff_name);
  195.             if (ctl) {
  196.                 int lineno;
  197.                 rewind(ctl);
  198.                 for (lineno = 1; fgets(input_line, sizeof(input_line), ctl); ++lineno) {
  199.                     char *p;
  200.                     if ((p = strchr(input_line, '\n')) != NULL)
  201.                         *p = '\0';
  202.                     if ((p = strchr(input_line, '#')) != NULL)
  203.                         *p = '\0';
  204.                     if ((p = strtok(input_line, " \t")) == NULL)
  205.                         continue;
  206.                     if (!strnicmp(p, work, strlen(work))) {
  207.                         if ((p = strtok(NULL, " \t")) == NULL)
  208.                             continue;
  209.                         if (sscanf(p, "%d,%d,%d", &kilos, &arts, &days) != 3)
  210.                             printf("%s: invalid syntax in line %d of control file\n", progname, lineno);
  211.                         }
  212.                     }            
  213.                 }
  214.             expire(work, kilos, arts, days);
  215.             } while (findnext(&ff) == 0);
  216.  
  217.     sprintf(work, "%s/*.*", dir);
  218.     if (findfirst(work, &ff, FA_DIREC) == 0)
  219.         do {
  220.             if (ff.ff_name[0] != '.') {
  221.                 sprintf(work, "%s/%s", dir, ff.ff_name);
  222.                 walk_dirs(work, ctl);
  223.                 }
  224.             } while(findnext(&ff) == 0);
  225.     }
  226.  
  227. mlock(char *dir, char *id)  /* from KA9Q */
  228.     {
  229.     char lockname[80];
  230.     int fd;
  231.  
  232.     /* Try to create the lock file in an atomic operation */
  233.     sprintf(lockname,"%s/%s.lck",dir,id);
  234. #ifdef        AMIGA
  235.     /* don't ask, really, just don't ask... I'd do file locking on
  236.      * an Amiga much more differently than this.
  237.      */
  238.     if(access(lockname, 0) == 0)
  239.         return -1;
  240. #endif
  241.     if((fd = open(lockname, O_WRONLY|O_EXCL|O_CREAT,0600)) == -1)
  242.         return -1;
  243.     close(fd);
  244.     return 0;
  245.     }
  246.  
  247. rmlock(char *dir, char *id)  /* from KA9Q */
  248.     {
  249.     char lockname[80];
  250.     sprintf(lockname,"%s/%s.lck",dir,id);
  251.     return(unlink(lockname));
  252.     }
  253.  
  254.